/**
 * @fileoverview 实现JS命名空间的管理，模块的定义，与自动加载依赖模块的脚本文件。
 * @author Liangdong | Esoul | pillar0514@gmail.com | liangdong2@staff.sina.com.cn
 */
(function(){
	
	var that = {},
		jsParent = null,
		doc = document,
		slice = Array.prototype.slice,
		RequireCache = [],
		JSManager = {},
		ModuleCache = {};

	/**
	 * @method bind 返回一个闭包
	 * @param {Function} fn 要操作的函数
	 * @param {Object} bind 要绑定的对象
	 * @param {Array} args 要插入的参数
	 * @return {Function} 绑定了引用对象的函数
	 */
	function $bind(fn, bind, args){
		return function(){
			return fn.apply(bind, slice.call(arguments).concat(args));
		};
	}

	/**
	 * @method each 遍历一个对象
	 * @param {Object} obj 可遍历的对象
	 * @param {Function} fn 要操作的函数
	 * @param {Object} bind 遍历函数要绑定的对象
	 */
	function $each(obj, fn, bind){
		for(var key in obj){
			fn.call(bind, obj[key], key, obj);
		}
	}

	/**
	 * @method loadjs 加载一个JS文件
	 * @param {String} strsrc JS文件的地址
	 */
	function loadjs(strsrc){
        var js = doc.createElement('script');
		js.type = 'text/javascript';
		js.charset = JSManager.$charset;
		js.src = strsrc;
		if(!jsParent){ jsParent = doc.getElementsByTagName('head')[0]; }
        jsParent.appendChild(js);
	}

	/**
	 * @method getModule 依据模块名称，获取一个模块管理器，不存在就创建一个。管理器负责记录模块的加载状态，供自动依赖机制使用。
	 * @param {String} mName 对应的模块名称
	 * @return {Object} module 依据模块名称生成的模块管理器
	 * @extrainfo module.state : { 1 : 'requesting', 2 : 'loaded', 3 : 'ready' }
	 */
	function getModule(mName){
		return ( ModuleCache[mName] = ModuleCache[mName] || { onReady : [] } ) ;
	}
	
	/**
	 * @method loadModule 加载一个模块
	 * @param {String} mName 模块的名称
	 */
	function loadModule(mName){
		var module = getModule(mName);
		if(module.state){ return; }
		module.state = 1;
		loadjs( (JSManager.$basepath || '') + mName.split('.').join('/') + '.js?version=' + JSManager.$version );
	}

	/**
	 * @method setModuleReady 设置模块加载成功
	 * @param {String} mName 模块的名称
	 * @param {Function} maker 模块构造函数
	 */
	function setModuleReady(mName){
		var arrName = (mName || '').split('.'),
			ns = that,
			module = getModule(mName);
		if(module.state === 3){return;}
		$each(arrName, function(name, index){
			if(!ns[name]){ ns[name] = {}; }
			if(index === arrName.length - 1 + ''){
				ns[name] =  module.maker(that) || {};
			}
			ns = ns[name];
		});
		module.state = 3;
		$each(module.onReady, function(fn){ fn(); });
		delete module.onReady;
		delete module.requires;
		delete module.maker;
	}

	/**
	 * @method checkDepend 检查模块依赖文件是否就绪
	 * @param {String} mName 模块的名称
	 */
	function checkDepend(mName){
		var requireNameList = {};
		var requires = getModule(mName).requires;
		(function(requireName){
			if(!requireName){
				var fnCheck = arguments.callee;
				$each(requires, function(name, index){
					if(name){
						requireNameList[name] = index;
						if(getModule(name).state === 3){
							requires[index] = '';
						}else{
							loadModule( name );
							getModule(name).onReady.push( $bind(fnCheck, null, [name]) );
						}
					}
				});
			}else{
				requires[ requireNameList[requireName] ] = '';
			}
			if(!requires.join('')){
				setModuleReady(mName);
			}
		})();
	}

	/**
	 * @method register 注册一个模块
	 * @param {String} mName 模块的名称
	 * @param {Function} maker 模块构造函数
	 */
	function register(mName, maker){		
		var module = getModule(mName);
		if(module.state >= 2){
			throw('The "' + mName + '" has been registered!!!');
		}
		module.state = 2;
		module.requires = [].concat(RequireCache);
		module.maker = maker;
		RequireCache.length = 0;
		
		checkDepend(mName);
	}

	/**
	 * @method $Import 加载（引入）一个模块
	 * @param {String} name 模块的名称
	 */
	function $Import(name){
		RequireCache.push(name);
	}

//---------------------------
	//参数配置区：
	var spaceName = 'SPORE';				//定义顶层命名空间的名称
	var managerName = '$JSManager';			//要暴露出去的JS管理器的名称
	var regName = 'register';				//要暴露出去的注册组件函数的名称
	var impName = '$Import';				//要暴露出去的引用组件函数的名称
	JSManager.$basepath = 'js/';			//JS库所在的线上路径
	JSManager.$charset = 'utf-8';			//JS文件的编码	
	JSManager.$version = new Date() - 0;	//JS版本号
//---------------------------

	//适配器：
	that[impName] = $Import;
	that[regName] = register;
	that[managerName] = JSManager;
	ModuleCache[impName] = ModuleCache[regName] = ModuleCache[managerName] = {state:3};
	JSManager.$ModuleCache = ModuleCache;
	if(!this[spaceName]){
		this[spaceName] = that;
	}else{
		$each(that, function(prop, name){
			if(!this[spaceName][name]){
				this[spaceName][name] = prop;
			}else{
				throw('Lib "' + spaceName + '" exists the same prop: ' + name);
			}
		});
		that = this[spaceName];
	}

})();